#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
using std::endl;
using std::cout;
using std::ostream;

// compiler should insure/increase data locality
// as much as possible




class pack_str_array{

	private:
			char* _data;
			size_t* _sz_ptr;
			size_t _sz;

	public:
			pack_str_array(char* * str_array, size_t sz):_sz(sz){
					size_t total_sz=0;

					_sz_ptr = (size_t*) malloc(sizeof(size_t)*(sz));

					if (_sz_ptr){
						for (size_t ind=0; ind < sz; ind++){
							// *(_sz_ptr + ind) = trlen(*(str_array+ind));
							total_sz+=strlen(str_array[ind])+1;
							_sz_ptr[ind]= total_sz; //_sz_ptr stores the total size of the first ind string, or the address of the ind+1-th string
							// total_sz+=_sz_ptr[ind]_sz_ptr[ind]+1;
						}
						}
					else
						{
							throw "Can not allocate memory for _sz_ptr in class pack_str_array!";
						}
				

					_data = (char*)malloc(_sz_ptr[sz-1]); // each c str end with a '\0' char
					if(_data){
						strcpy(_data, str_array[0]);
						for (size_t ind=1; ind < sz; ind++){
								strcpy(_data+_sz_ptr[ind-1], str_array[ind]);
							}
					}
					else
						{
								throw "Can not resize _sz_ptr in class pack_str_array!";
						}
					
					
					
			}

			~pack_str_array() {free(_sz_ptr);free(_data);}

			char* operator[](const size_t& ind) const{
					if (ind==0){
							return _data;
					}
					else if (ind<_sz){
						return _data+_sz_ptr[ind-1];
					}
					else{
						throw "out of range!";
					}
			}

			friend ostream& operator<<(ostream& os, const pack_str_array& psa );

};

ostream& operator<<(ostream& os, const pack_str_array& psa ) {
	os << psa._data;
	for (size_t ind=1; ind < psa._sz; ind++){
		os<<", " <<psa._data+psa._sz_ptr[ind-1];						
	}

	return os;
}

int main() {
	char** ss;
	ss = new char*[3];
	ss[0]="string 0";
	ss[1]="string 1";
	ss[2]="string 2";
	pack_str_array psa(ss,3);
	cout << psa[0] << endl;
	cout << psa[1] << endl;
	cout << psa[2] << endl;
	delete[] ss;

	return 0;
}
